<script setup lang="ts">
import type { Role, RoleMenuTreeNode } from '#/api';

import { computed, ref, watch } from 'vue';

import { Alert, Button, Input, message, Modal, Space, Spin, Tree } from 'ant-design-vue';
import { SearchOutlined } from '@ant-design/icons-vue';

import { assignRoleMenusApi, getRoleMenuTree } from '#/api';

interface Props {
  open: boolean;
  roleData?: Role;
}

const props = defineProps<Props>();
const emit = defineEmits(['update:open', 'success']);

const confirmLoading = ref(false);
const loading = ref(false);

// 菜单树数据
const menuTreeData = ref<RoleMenuTreeNode[]>([]);
// 过滤后的菜单树数据
const filteredMenuTreeData = ref<RoleMenuTreeNode[]>([]);
// 搜索关键词
const searchKeyword = ref('');
// 选中的节点ID（菜单和按钮）
const checkedKeys = ref<number[]>([]);
// 半选的节点ID
const halfCheckedKeys = ref<number[]>([]);
// 展开的节点ID
const expandedKeys = ref<number[]>([]);

// 监听弹窗显示状态和角色数据变化
watch(
  () => [props.open, props.roleData] as const,
  async ([open, roleData]) => {
    if (open && roleData?.id) {
      await loadRoleMenuTree(roleData.id);
    } else {
      // 关闭弹窗时清空搜索
      searchKeyword.value = '';
    }
  },
  { immediate: true },
);

// 给节点添加自定义类名（用于样式控制）
function addCustomClassName(nodes: RoleMenuTreeNode[]): any[] {
  return nodes.map((node) => ({
    ...node,
    className: node.menuType === 3 ? 'button-node' : '',
    children: node.children ? addCustomClassName(node.children) : undefined,
  }));
}

// 过滤菜单树（根据搜索关键词）
const displayMenuTreeData = computed(() => {
  let data = menuTreeData.value;

  if (searchKeyword.value.trim()) {
    const keyword = searchKeyword.value.toLowerCase().trim();

    // 递归过滤节点
    function filterNodes(nodes: RoleMenuTreeNode[]): RoleMenuTreeNode[] {
      const result: RoleMenuTreeNode[] = [];

      for (const node of nodes) {
        // 检查当前节点是否匹配
        const isMatch = node.menuName.toLowerCase().includes(keyword);

        // 递归过滤子节点
        const filteredChildren = node.children
          ? filterNodes(node.children)
          : [];

        // 如果当前节点匹配，或者有匹配的子节点，则保留
        if (isMatch || filteredChildren.length > 0) {
          result.push({
            ...node,
            children: filteredChildren.length > 0 ? filteredChildren : node.children,
          });
        }
      }

      return result;
    }

    data = filterNodes(data);
  }

  // 添加自定义类名
  return addCustomClassName(data);
});

// 监听搜索关键词变化，自动展开匹配的节点
watch(searchKeyword, (newKeyword) => {
  if (newKeyword.trim()) {
    // 有搜索关键词时，展开所有匹配的节点
    expandedKeys.value = extractAllIds(displayMenuTreeData.value);
  } else {
    // 清空搜索时，恢复默认展开状态
    expandedKeys.value = extractAllIds(menuTreeData.value);
  }
});

// 加载角色菜单树
async function loadRoleMenuTree(roleId: number) {
  try {
    loading.value = true;
    const menuTree = await getRoleMenuTree(roleId);

    // 设置菜单树数据
    menuTreeData.value = menuTree;

    // 提取已选中的节点ID（只提取叶子节点，避免父节点自动选中）
    const selectedIds: number[] = [];

    function extractLeafSelections(nodes: RoleMenuTreeNode[]) {
      for (const node of nodes) {
        // 如果节点被选中
        if (node.checked) {
          // 如果有子节点，递归处理
          if (node.children && node.children.length > 0) {
            extractLeafSelections(node.children);
          } else {
            // 叶子节点，添加到选中列表
            selectedIds.push(node.id);
          }
        } else if (node.children && node.children.length > 0) {
          // 即使当前节点未选中，也要递归检查子节点
          extractLeafSelections(node.children);
        }
      }
    }

    extractLeafSelections(menuTreeData.value);

    // 设置选中的ID
    checkedKeys.value = selectedIds;

    // 默认展开所有节点
    expandedKeys.value = extractAllIds(menuTreeData.value);

    console.log('加载菜单树成功:', {
      总节点数: extractAllIds(menuTreeData.value).length,
      选中节点数: selectedIds.length,
      选中的ID: selectedIds,
    });
  } catch (error) {
    console.error('加载角色菜单树失败:', error);
    message.error('加载角色菜单树失败');
  } finally {
    loading.value = false;
  }
}

// 提取菜单树中的所有ID（包括菜单和按钮）
function extractAllIds(nodes: RoleMenuTreeNode[]): number[] {
  const ids: number[] = [];
  function traverse(node: RoleMenuTreeNode) {
    if (node.id) {
      ids.push(node.id);
    }
    if (node.children) {
      for (const child of node.children) {
        traverse(child);
      }
    }
  }
  for (const node of nodes) {
    traverse(node);
  }
  return ids;
}

// 统计按钮节点数量
function countButtonNodes(nodes: RoleMenuTreeNode[]): number {
  let count = 0;
  function traverse(node: RoleMenuTreeNode) {
    if (node.menuType === 3) {
      count++;
    }
    if (node.children) {
      for (const child of node.children) {
        traverse(child);
      }
    }
  }
  for (const node of nodes) {
    traverse(node);
  }
  return count;
}

// Tree 组件的选中事件
function onCheck(checkedKeysValue: any, e: any) {
  checkedKeys.value = checkedKeysValue.checked || checkedKeysValue;
  halfCheckedKeys.value = e.halfCheckedKeys || [];

  console.log('🔍 Tree 选中状态变化:', {
    checkedKeys: checkedKeys.value,
    halfCheckedKeys: halfCheckedKeys.value,
    合并后: [...checkedKeys.value, ...halfCheckedKeys.value],
  });
}

/**
 * 从菜单树中收集所有选中的节点ID
 * @param nodes 菜单树节点
 * @param leafCheckedIds 叶子节点的选中ID列表
 * @returns 所有选中的节点ID（包括父节点）
 */
function collectAllSelectedIds(nodes: RoleMenuTreeNode[], leafCheckedIds: number[]): number[] {
  const selectedIds: number[] = [];
  const leafIdSet = new Set(leafCheckedIds);

  function traverse(node: RoleMenuTreeNode): boolean {
    // 检查当前节点是否被选中
    let isSelected = leafIdSet.has(node.id);

    // 如果有子节点，递归检查
    if (node.children && node.children.length > 0) {
      let allChildrenSelected = true;
      let anyChildSelected = false;

      for (const child of node.children) {
        const childSelected = traverse(child);
        if (childSelected) {
          anyChildSelected = true;
        } else {
          allChildrenSelected = false;
        }
      }

      // 如果所有子节点都被选中，当前节点也应该被选中
      if (allChildrenSelected) {
        isSelected = true;
      }
      // 如果有任何子节点被选中，当前节点也应该被包含（半选状态）
      else if (anyChildSelected) {
        isSelected = true;
      }
    }

    // 如果当前节点被选中，添加到结果列表
    if (isSelected) {
      selectedIds.push(node.id);
    }

    return isSelected;
  }

  for (const node of nodes) {
    traverse(node);
  }

  return selectedIds;
}

// 确定
async function handleOk() {
  if (!props.roleData?.id) return;

  try {
    confirmLoading.value = true;

    // 收集所有选中的ID
    // checkedKeys: 完全选中的节点（叶子节点）
    // halfCheckedKeys: 半选中的父节点（部分子节点被选中）
    //
    // 注意：Ant Design Tree 组件的行为：
    // - checkedKeys 只包含叶子节点（最底层的节点）
    // - halfCheckedKeys 包含部分子节点被选中的父节点
    // - 如果所有子节点都被选中，父节点不会出现在任何数组中
    //
    // 解决方案：我们需要从树中收集所有选中的节点ID（包括完全选中的父节点）
    const menuIdList = collectAllSelectedIds(menuTreeData.value, checkedKeys.value);

    console.log('分配权限 - 详细信息:', {
      roleId: props.roleData.id,
      roleName: props.roleData.roleName,
      '完全选中的节点（叶子）': checkedKeys.value,
      '半选中的父节点': halfCheckedKeys.value,
      '最终传递的menuIdList': menuIdList,
      '总数量': menuIdList.length,
    });

    // 只传递角色ID和菜单ID列表（包含目录、菜单、按钮）
    await assignRoleMenusApi(props.roleData.id, menuIdList);
    message.success('分配权限成功');

    emit('success');
    handleCancel();
  } catch (error) {
    console.error('分配权限失败:', error);
    message.error('分配权限失败');
  } finally {
    confirmLoading.value = false;
  }
}

// 取消
function handleCancel() {
  emit('update:open', false);
  checkedKeys.value = [];
  halfCheckedKeys.value = [];
  expandedKeys.value = [];
  searchKeyword.value = '';
}
</script>

<template>
  <Modal
    :open="open"
    title="分配菜单权限"
    :confirm-loading="confirmLoading"
    width="650px"
    @ok="handleOk"
    @cancel="handleCancel"
  >
    <Spin :spinning="loading">
      <!-- 角色信息 -->
      <div class="mb-4 rounded-lg border border-blue-200 bg-gradient-to-r from-blue-50 to-indigo-50 p-3">
        <div class="flex items-center gap-4">
          <div class="flex items-center gap-2">
            <div class="flex h-8 w-8 items-center justify-center rounded-full bg-blue-500 text-white">
              <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
                <path d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z" />
              </svg>
            </div>
            <div>
              <div class="text-xs text-gray-500">当前角色</div>
              <div class="text-base font-semibold text-gray-900">{{ roleData?.roleName }}</div>
            </div>
          </div>
          <div class="h-8 w-px bg-blue-200"></div>
          <div>
            <div class="text-xs text-gray-500">角色编码</div>
            <div class="font-mono text-sm font-medium text-blue-600">{{ roleData?.roleCode }}</div>
          </div>
        </div>
      </div>

      <!-- 搜索框和操作按钮 -->
      <div class="mb-3 flex items-center gap-2">
        <Input
          v-model:value="searchKeyword"
          placeholder="搜索菜单或按钮名称..."
          allow-clear
          class="flex-1"
        >
          <template #prefix>
            <SearchOutlined />
          </template>
        </Input>
        <Button size="small" @click="expandedKeys = extractAllIds(displayMenuTreeData)">
          展开全部
        </Button>
        <Button size="small" @click="expandedKeys = []">
          收起全部
        </Button>
      </div>

      <!-- 统计信息 -->
      <div class="mb-3 text-sm text-gray-500">
        <span v-if="searchKeyword">找到 {{ extractAllIds(displayMenuTreeData).length }} 个匹配项</span>
        <span v-else>共 {{ extractAllIds(menuTreeData).length }} 个节点，已选中 {{ checkedKeys.length + halfCheckedKeys.length }} 个</span>
      </div>

      <!-- 权限树 -->
      <div class="rounded border border-gray-200">
        <div class="max-h-[450px] overflow-y-auto p-3">
          <Tree
            v-if="displayMenuTreeData.length > 0"
            checkable
            :tree-data="displayMenuTreeData"
            :field-names="{
              title: 'menuName',
              key: 'id',
              children: 'children',
              class: 'className',
            }"
            :checked-keys="checkedKeys"
            :expanded-keys="expandedKeys"
            @check="onCheck"
            @expand="(keys: number[]) => (expandedKeys = keys)"
          >
            <template #title="{ menuName, menuType }">
              <span class="inline-flex items-center gap-2">
                <!-- 目录 -->
                <span v-if="menuType === 1" class="inline-flex h-6 w-6 items-center justify-center rounded-md bg-gradient-to-br from-amber-400 to-orange-500 shadow-sm">
                  <svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5 text-white" viewBox="0 0 20 20" fill="currentColor">
                    <path d="M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" />
                  </svg>
                </span>
                <!-- 菜单 -->
                <span v-else-if="menuType === 2" class="inline-flex h-6 w-6 items-center justify-center rounded-md bg-gradient-to-br from-blue-400 to-blue-600 shadow-sm">
                  <svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5 text-white" viewBox="0 0 20 20" fill="currentColor">
                    <path d="M3 4a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H4a1 1 0 01-1-1V4zM3 10a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H4a1 1 0 01-1-1v-6zM14 9a1 1 0 00-1 1v6a1 1 0 001 1h2a1 1 0 001-1v-6a1 1 0 00-1-1h-2z" />
                  </svg>
                </span>
                <!-- 按钮 - 使用标签样式 -->
                <span v-else-if="menuType === 3" class="inline-flex items-center gap-1.5 rounded-full border border-green-300 bg-gradient-to-r from-green-50 to-emerald-50 px-2.5 py-0.5 text-xs font-medium text-green-700 shadow-sm">
                  <svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" viewBox="0 0 20 20" fill="currentColor">
                    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
                  </svg>
                  {{ menuName }}
                </span>
                <!-- 非按钮节点显示名称 -->
                <span v-if="menuType !== 3" :class="menuType === 1 ? 'font-semibold text-gray-800' : 'text-gray-700'">
                  {{ menuName }}
                </span>
              </span>
            </template>
          </Tree>
          <div v-else class="py-8 text-center text-gray-400">
            {{ searchKeyword ? '未找到匹配的权限' : '暂无权限数据' }}
          </div>
        </div>
      </div>
    </Spin>
  </Modal>
</template>

<style scoped>
:deep(.ant-tree) {
  font-size: 14px;
}

/* 树节点样式优化 */
:deep(.ant-tree-treenode) {
  padding: 2px 0;
}

:deep(.ant-tree-node-content-wrapper) {
  padding: 2px 4px;
  border-radius: 4px;
  transition: background-color 0.2s;
}

:deep(.ant-tree-node-content-wrapper:hover) {
  background-color: #f5f5f5;
}

/* 复选框样式优化 */
:deep(.ant-tree-checkbox) {
  margin-top: 0;
  margin-right: 8px;
}

:deep(.ant-tree-checkbox-inner) {
  border-radius: 4px;
  border-color: #d9d9d9;
  transition: all 0.2s;
}

:deep(.ant-tree-checkbox-checked .ant-tree-checkbox-inner) {
  background-color: #1890ff;
  border-color: #1890ff;
}

:deep(.ant-tree-checkbox-indeterminate .ant-tree-checkbox-inner::after) {
  background-color: #1890ff;
}

/* 按钮节点特殊样式 - 隐藏复选框 */
:deep(.button-node .ant-tree-checkbox) {
  display: none;
}

/* 按钮节点左侧缩进对齐 */
:deep(.button-node) {
  margin-left: 24px;
}

/* 按钮节点的内容包装器 */
:deep(.button-node .ant-tree-node-content-wrapper) {
  padding-left: 0;
}

/* 按钮节点选中状态 - 改变标签颜色 */
:deep(.ant-tree-treenode-checkbox-checked.button-node .border-green-300) {
  background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
  border-color: #52c41a;
  color: white;
  box-shadow: 0 2px 4px rgba(82, 196, 26, 0.3);
}

:deep(.ant-tree-treenode-checkbox-checked.button-node .border-green-300 svg) {
  color: white;
}

/* 按钮节点未选中状态 */
:deep(.button-node .border-green-300) {
  cursor: pointer;
  transition: all 0.2s;
}

:deep(.button-node .border-green-300:hover) {
  background: linear-gradient(to right, #f0fdf4 0%, #d1fae5 100%);
  border-color: #86efac;
  transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(34, 197, 94, 0.2);
}
</style>
